package org.msb.code.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @Package org.msb.code.thread
 * @PROJECT_NAME: question
 * @DESCRIPTION:
 * @USER: zhuchenglin
 * @DATE: 2022/6/3 19:21
 */
public class TestAddSize {
    /**
     * 实现一个容器，提供两个方法add,size
     * 写两个线程，线程1添加10个元素到容器中，线程2实现监控元素的个数，当个数到5个时，线程2给出提示并结束
     */
    static class TestWithoutVolatile {

        public static void main(String[] args) {
            List<Integer> list = new ArrayList<>();
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    System.out.println(i);
                    list.add(i);
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            new Thread(() -> {
                while (true) {
                    if (list.size() == 5) {
                        break;
                    }
                }
                System.out.println(list);
            }).start();
        }
    }

    static class TestWithVolatile {

        volatile static List<Integer> list = new ArrayList<>();

        public static void main(String[] args) {
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    System.out.println(i);
                    list.add(i);
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            new Thread(() -> {
                while (true) {
                    if (list.size() == 5) {
                        break;
                    }
                }
                System.out.println(list);
            }).start();
        }
    }

    static class TestSync {

        static List<Object> list = new ArrayList<>();

        synchronized void add(Object o) {
            list.add(o);
        }

        synchronized int size() {
            return list.size();
        }

        public static void main(String[] args) {
            TestSync c = new TestSync();
            Thread t1 = new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    System.out.println(i);
                    c.add(i);
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t1.start();

            new Thread(() -> {
                while (true) {
                    if (c.size() == 5) {
                        break;
                    }
                }
                System.out.println(list);
            }).start();
        }
    }

    static class TestNotifyHoldingLock {

        static List<Object> list = new ArrayList<>();

        void add(Object o) {
            list.add(o);
        }

        int size() {
            return list.size();
        }


        public static void main(String[] args) {
            TestNotifyHoldingLock c = new TestNotifyHoldingLock();

            final Object lock = new Object();

            new Thread(() -> {
                System.out.println("t2启动");
                synchronized (lock) {
                    if (c.size() != 5) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("t2 end");
                    lock.notify();
                }
            }, "t2").start();

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            new Thread(() -> {
                System.out.println("t1启动");
                synchronized (lock) {
                    for (int i = 0; i < 10; i++) {
                        c.add(new Object());
                        System.out.println("add" + i);
                        if (c.size() == 5) {
                            // 不释放锁，叫醒了但是t1还在执行，t2唤醒了但是一直等待
                            lock.notify();
                            try {
                                // 自己让出锁
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, "t1").start();
        }
    }

    static class TestCountDownLatch {

        static List<Object> list = new ArrayList<>();

        void add(Object o) {
            list.add(o);
        }

        int size() {
            return list.size();
        }

        public static void main(String[] args) {
            TestCountDownLatch c = new TestCountDownLatch();
            CountDownLatch c1 = new CountDownLatch(1);
            CountDownLatch c2 = new CountDownLatch(1);

            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    c.add(new Object());
                    System.out.println("add" + i);
                    if (c.size() == 5) {
                        c1.countDown();
                        try {
                            c2.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }


            }, "t1").start();

            new Thread(() -> {
                if (c.size() != 5) {
                    try {
                        c1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                c2.countDown();
                System.out.println("t2 end");
            }, "t2").start();

        }
    }

    static class TestLockSupport {

        static List<Object> list = new ArrayList<>();

        void add(Object o) {
            list.add(o);
        }

        int size() {
            return list.size();
        }

        static Thread t1 = null, t2 = null;

        public static void main(String[] args) {
            TestLockSupport c = new TestLockSupport();

            t2 = new Thread(() -> {
                LockSupport.park();
                System.out.println("t2 end");
                LockSupport.unpark(t1);
            }, "t2");
            t1 = new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    c.add(new Object());
                    System.out.println("add" + i);
                    if (c.size() == 5) {
                        LockSupport.unpark(t2);
                        LockSupport.park();
                    }
                }
            }, "t1");

            t2.start();
            t1.start();
        }
    }

    static class TestSemaphore {

        static List<Object> list = new ArrayList<>();

        void add(Object o) {
            list.add(o);
        }

        int size() {
            return list.size();
        }

        static Thread t1 = null, t2 = null;

        public static void main(String[] args) {
            TestSemaphore c = new TestSemaphore();
            Semaphore semaphore = new Semaphore(1);

           t1 = new Thread(() -> {
               try {
                   semaphore.acquire();
                   for (int i = 0; i < 5; i++) {
                       c.add(new Object());
                       System.out.println("add" + i);
                   }
                   semaphore.release();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }

               try {
                   t2.start();
                   t2.join();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               try {
                    semaphore.acquire();
                    for (int i = 5; i < 10; i++) {
                        c.add(new Object());
                        System.out.println("add" + i);
                    }
                   semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }, "t1");

            t2 = new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println("t2 end");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "t2");

            t1.start();

        }
    }
}
